﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using Grain.Crm.DataMigrator.CrmServices;
using Grain.Crm.DataMigrator.Imports;
using Grain.Crm.DataMigrator.Infrastructure;
using Grain.Crm.ExcelExtractor;
using Grain.Crm.ExcelExtractor.Input;
using NUnit.Framework;
using Rhino.Mocks;

namespace Grain.Crm.DataMigrator.Test
{
    [TestFixture]
    public class ImportTask_Unit
    {
        [Test]
        public void ShouldFindExistingEntityByValueFromConstantResolver()
        {
            SetupStubData();
            var builder = new Builder(null, null, _crmServiceStub, new Container());

            var importTask = new ImportEntityTask("contact");
            importTask.SearchAttributes = new SearchAttribute[]
                                              {
                                                  new SearchAttribute("fullname", new ConstantValueResolver("Peter Mrkva")),
                                              };

            importTask.Build(builder);
            importTask.Execute();

            Assert.AreEqual(ImportMode.Update, importTask.ImportMode);
        }

        [Test]
        public void ShouldNotFindExistingEntityByValueFromConstantResolver()
        {
            SetupStubData();
            var builder = new Builder(null, null, _crmServiceStub, new Container());

            var importTask = new ImportEntityTask("contact");
            importTask.SearchAttributes = new SearchAttribute[]
                                              {
                                                  new SearchAttribute("fullname", new ConstantValueResolver("* Peter Mrkva")),
                                              };

            importTask.Build(builder);
            importTask.Execute();

            Assert.AreEqual(ImportMode.CreateNew, importTask.ImportMode);
        }

        [Test]
        public void ShouldFindExistingEntityByValueFromSheetResolver()
        {
            SetupStubData();
            var builder = new Builder("Full Name,E-Mail", "Peter Mrkva, peter.mrkva@gmail.com", _crmServiceStub, new Container());

            var importTask = new ImportEntityTask("contact");
            importTask.SearchAttributes = new SearchAttribute[]
                                              {
                                                  new SearchAttribute("fullname", new SheetValueResolver("Full Name") ),
                                              };

            importTask.Build(builder);
            importTask.Execute();

            Assert.AreEqual(ImportMode.Update, importTask.ImportMode);
        }

        [Test]
        public void ShouldNotFindExistingEntityByValueFromSheetResolver()
        {
            SetupStubData();
            var builder = new Builder("Full Name,E-Mail", "* Peter Mrkva,peter.mrkva@gmail.com", _crmServiceStub, new Container());

            var importTask = new ImportEntityTask("contact");
            importTask.SearchAttributes = new SearchAttribute[]
                                              {
                                                  new SearchAttribute("fullname", new SheetValueResolver("Full Name") ),
                                              };

            importTask.Build(builder);
            importTask.Execute();

            Assert.AreEqual(ImportMode.CreateNew, importTask.ImportMode);
        }

        [Test]
        public void ShouldFindExistingEntityByValueFromCrmResolver()
        {
            SetupStubData();
            var builder = new Builder("CV,Contact", "Cv-tempID,Peter Mrkva", _crmServiceStub, new Container());

            var importTask = new ImportEntityTask("new_curriculumvitae");
            importTask.SearchAttributes = new SearchAttribute[]
                                              {
                                                  new SearchAttribute("new_contactid", 
                                                      new CrmIdResolver("contact", new[] {"fullname"}, new[] {new ConstantValueResolver("Peter Mrkva")}) ),
                                              };

            importTask.Build(builder);
            importTask.Execute();

            Assert.AreEqual(ImportMode.Update, importTask.ImportMode);
        }

        [Test]
        public void ShouldNotFindExistingEntityByValueFromCrmResolver()
        {
            SetupStubData();
            var builder = new Builder("CV,Contact", "Cv-tempID,Peter Mrkva", _crmServiceStub, new Container());

            var importTask = new ImportEntityTask("new_curriculumvitae");
            importTask.SearchAttributes = new SearchAttribute[]
                                              {
                                                  new SearchAttribute("new_contactid", 
                                                      new CrmIdResolver("contact",new[] { "fullname"},new[] { new ConstantValueResolver("* Peter Mrkva")}) ),
                                              };

            importTask.Build(builder);
            importTask.Execute();

            Assert.AreEqual(ImportMode.CreateNew, importTask.ImportMode);
        }

        [Test]
        public void ShouldFindExistingEntityByValueFromCrmResolverAndSheetResolver()
        {
            SetupStubData();
            var builder = new Builder("CV,Contact,Language", "Cv-tempID,Peter Mrkva,English", _crmServiceStub, new Container());

            var importTask = new ImportEntityTask("new_curriculumvitae");
            importTask.SearchAttributes = new SearchAttribute[]
                                              {
                                                  new SearchAttribute("new_contactid", 
                                                      new CrmIdResolver("contact", new[] { "fullname"},new[] {  new SheetValueResolver("Contact")}) ),

                                                  new SearchAttribute("new_languageid",
                                                      new CrmIdResolver("new_language",new[] {  "new_name"}, new[] { new SheetValueResolver("Language")})
                                                      ), 
                                              };

            importTask.Build(builder);
            importTask.Execute();

            Assert.AreEqual(ImportMode.Update, importTask.ImportMode);
        }

        [Test]
        public void ShouldAppendValueToContent()
        {
            SetupStubData();
            var builder = new Builder("CV,Contact,Language", "Cv-tempID,Peter Mrkva,English", _crmServiceStub, new Container());

            var importTask = new ImportEntityTask("new_curriculumvitae");
            importTask.ValueAppenders = new[] { new ValueAppender("AppendedHeader", new ConstantValueResolver("AppendedValue")) };
            importTask.Build(builder);

            importTask.Execute();

            Assert.AreEqual("CV,Contact,Language,AppendedHeader", importTask.HeaderRow);
            Assert.AreEqual("Cv-tempID,Peter Mrkva,English,AppendedValue", importTask.ContentRow);
        }

        [Test]
        public void ShouldFindEntityAndAddPrimaryKey()
        {
            SetupStubData();
            var builder = new Builder("Full Name,E-Mail", "Peter Mrkva,peter.mrkva@gmail.com", _crmServiceStub, new Container());

            var importTask = new ImportEntityTask("contact");
            importTask.SearchAttributes = new SearchAttribute[]
                                              {
                                                  new SearchAttribute("fullname", new SheetValueResolver("Full Name") ),
                                              };

            importTask.PrimaryKeyAppender = new ValueAppender(
                "Contact",
                new CrmIdResolver("contact", new[] { "fullname" }, new[] { new SheetValueResolver("Full Name") }));

            importTask.Build(builder);
            importTask.Execute();

            Assert.AreEqual("Full Name,E-Mail,Contact", importTask.HeaderRow);
            Assert.AreEqual("Peter Mrkva,peter.mrkva@gmail.com," + MrkvaId.ToString(), importTask.ContentRow);
        }

        [Test]
        public void ShouldReturnScalarDataFromCrmQuery()
        {
            SetupStubData();
            var builder = new Builder(null, null, _crmServiceStub, new Container());

            var resolver = new CrmValueResolver(
                "contact", "address1_city",
                new[] { "fullname" }, new[] { new ConstantValueResolver("Peter Mrkva") });

            resolver.Build(builder);

            var value = resolver.Resolve();

            Assert.AreEqual("Kosice", value);
        }

        [Test]
        public void ShouldReturnKeyDataFromCrmQuery()
        {
            SetupStubData();
            var builder = new Builder(null, null, _crmServiceStub, new Container());

            var resolver = new CrmValueResolver(
                "contact", "contactid",
                new[] { "fullname" }, new[] { new ConstantValueResolver("Peter Mrkva") });

            resolver.Build(builder);

            var value = resolver.Resolve();

            Assert.AreEqual(MrkvaId.ToString(), value);
        }

        [Test]
        public void ShouldReturnPicklistDataFromCrmQuery()
        {
            SetupStubData();
            var builder = new Builder(null, null, _crmServiceStub, new Container());

            var resolver = new CrmValueResolver(
                "contact", "accountrolecode",
                new[] { "fullname" }, new[] { new ConstantValueResolver("Peter Mrkva") });

            resolver.Build(builder);

            var value = resolver.Resolve();
            Assert.AreEqual("Picklist_name1", value);

        }

        [Test]
        public void ShouldResolveContainerCrmValue()
        {
            SetupStubData();

            var builder = new Builder(null, null, _crmServiceStub, new Container());

            var container = new Container();
            container.Add(new ContainerEntry()
                              {
                                  Key = "@Contact.Address",
                                  Value = new CrmValueResolver(
                                      "contact", "address1_city", new string[] { "fullname" }, new[] { new ConstantValueResolver("Peter Mrkva") })
                              });

            container.Build(builder);

            var value = container.GetByKey("@Contact.Address");

            Assert.AreEqual("Kosice", value);
        }

        [Test]
        public void ShouldResolveContainerValue_withSheetResolver()
        {
            SetupStubData();

            var builder = new Builder("Full Name", "Peter Mrkva", _crmServiceStub, new Container());

            var container = new Container();
            container.Add(new ContainerEntry()
                              {
                                  Key = "@Contact.name",
                                  Value = new SheetValueResolver("Full Name")
                              });

            container.Build(builder);

            var value = container.GetByKey("@Contact.name");

            Assert.AreEqual("Peter Mrkva", value);
        }

        [Test]
        public void ShouldResolveContainerValue_withCrmAndSheetResolversCombined()
        {
            SetupStubData();

            var builder = new Builder("Full Name", "Peter Mrkva", _crmServiceStub, new Container());

            var container = new Container();
            container.Add(new ContainerEntry()
            {
                Key = "@Contact.Address",
                Value = new CrmValueResolver(
                    "contact", "address1_city", new string[] { "fullname" }, new[] { new SheetValueResolver("Full Name") })
            });

            container.Build(builder);

            var value = container.GetByKey("@Contact.Address");

            Assert.AreEqual("Kosice", value);
        }

        [Test]
        public void ShouldResolveSharedContainerValue_withSheetResolver()
        {
            SetupStubData();

            var sharedContainer = new Container();

            var builder = new Builder("Full Name,Address", "Peter Mrkva,Kosice", _crmServiceStub, sharedContainer);

            var container = new Container();
            container.Add(new ContainerEntry()
            {
                Key = "@Contact.name",
                Value = new SheetValueResolver("Full Name")
            });

            container.Build(builder);

            var value = sharedContainer.GetByKey("@Contact.name");

            Assert.AreEqual("Peter Mrkva", value);
        }

        [Test]
        public void ShouldResolveSharedContainerValue_withSheetResolverAndCrmResolver()
        {
            SetupStubData();

            var sharedContainer = new Container();

            var builder = new Builder("Full Name,Address", "Peter Mrkva,Kosice", _crmServiceStub, sharedContainer);

            var container1 = new Container();
            container1.Add(new ContainerEntry()
            {
                Key = "@Contact.name",
                Value = new SheetValueResolver("Full Name")
            });

            container1.Build(builder);

            var container2 = new Container();
            container2.Add(new ContainerEntry()
            {
                Key = "@Contact.address",
                Value = new CrmValueResolver(
                           "contact", "address1_city", new string[] { "fullname" }, new[] { new SheetValueResolver("Full Name") })

            });

            container2.Build(builder);

            var containerResolverName = new ContainerValueResolver() { Key = "@Contact.name" };
            containerResolverName.Build(builder);
            var valueName = containerResolverName.Resolve();

            var containerResolverAddress = new ContainerValueResolver() { Key = "@Contact.address" };
            containerResolverAddress.Build(builder);
            var valueAddress = containerResolverAddress.Resolve();

            Assert.AreEqual("Peter Mrkva", valueName);
            Assert.AreEqual("Kosice", valueAddress);
        }

        [Test]
        public void ShouldCreateEmptyImportProcessAndExecuteWithNoResults()
        {
            SetupStubData();
            var builder = new Builder(null, null, _crmServiceStub, new Container());

            var task1 = new ImportEntityTask("contact");
            var task2 = new ImportEntityTask(EntityName.new_curriculumvitae.ToString());

            var process = new SheetImportProcess();
            process.ImportTasks = new[] { task1, task2 };
            process.Build(builder);
            process.Execute();
        }

        [Test]
        public void ShouldCreateImportProcessAndExecuteWithResults()
        {
            SetupStubData();

            var builder = new Builder("Full Name,E-Mail", "Peter Mrkva,peter.mrkva@gmail.com", _crmServiceStub, new Container());

            var importTask1 = new ImportEntityTask("contact");
            importTask1.SearchAttributes = new SearchAttribute[]
                                              {
                                                  new SearchAttribute("fullname", new SheetValueResolver("Full Name") ),
                                              };

            importTask1.PrimaryKeyAppender = new ValueAppender(
                "Contact",
                new CrmIdResolver("contact", new[] { "fullname" }, new[] { new SheetValueResolver("Full Name") }));

            var importTask2 = new ImportEntityTask(EntityName.new_curriculumvitae.ToString());

            var process = new SheetImportProcess();
            process.ImportTasks = new[] { importTask1, importTask2 };
            process.Build(builder);
            process.Execute();
        }


       
        #region Private
        private void SetupStubData()
        {
            _crmServiceStub = MockRepository.GenerateStub<ICrmService>();

            //setup query:
            var query = ImportsHelper.CreateQuery("contact", new string[] { "fullname" }, new string[] { "Peter Mrkva" });
            _crmServiceStub.Stub(a => a.RetrieveMultiple(Arg<QueryByAttribute>.Is.Equal(query))).Return(
                new BusinessEntityCollection() { BusinessEntities = new BusinessEntity[] { new contact() { contactid = new Key() { Value = MrkvaId }, address1_city = "Kosice", accountrolecode = new Picklist() { name = "Picklist_name1", Value = 1 } } } });

            query = ImportsHelper.CreateQuery("new_curriculumvitae", new string[] { "new_contactid" }, new string[] { MrkvaId.ToString() });
            _crmServiceStub.Stub(a => a.RetrieveMultiple(Arg<QueryByAttribute>.Is.Equal(query))).Return(
                new BusinessEntityCollection() { BusinessEntities = new BusinessEntity[] { new new_curriculumvitae() { new_curriculumvitaeid = new Key() { Value = CvId } } } });

            query = ImportsHelper.CreateQuery("new_language", new string[] { "new_name" }, new string[] { "English" });
            _crmServiceStub.Stub(a => a.RetrieveMultiple(Arg<QueryByAttribute>.Is.Equal(query))).Return(
                new BusinessEntityCollection() { BusinessEntities = new BusinessEntity[] { new new_language() { new_languageid = new Key() { Value = LangId } } } });

            query = ImportsHelper.CreateQuery("new_curriculumvitae", new string[] { "new_contactid", "new_languageid" }, new string[] { MrkvaId.ToString(), LangId.ToString() });
            _crmServiceStub.Stub(a => a.RetrieveMultiple(Arg<QueryByAttribute>.Is.Equal(query))).Return(
                new BusinessEntityCollection() { BusinessEntities = new BusinessEntity[] { new new_curriculumvitae() { new_curriculumvitaeid = new Key() { Value = CvId } } } });


            //any other query returns empty collection:
            _crmServiceStub.Stub(a => a.RetrieveMultiple(Arg<QueryByAttribute>.Is.NotEqual(query))).Return(
               new BusinessEntityCollection() { BusinessEntities = new BusinessEntity[0] });

        }

        private ICrmService _crmServiceStub;
        private Guid MrkvaId = Guid.NewGuid();
        private Guid CvId = Guid.NewGuid();
        private Guid LangId = Guid.NewGuid();

        #endregion

    }
}
